package main

import (
	"crypto/ecdsa"
	"encoding/hex"
	"fmt"
	"log"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	ethcrypto "github.com/ethereum/go-ethereum/crypto"
)

func ECDSAPrivKeyToStr(privKey *ecdsa.PrivateKey) string {
	return hex.EncodeToString(ethcrypto.FromECDSA(privKey))
}

func StrToECDSAPrivKey(privateKeyString string) (*ecdsa.PrivateKey, error) {
	decodedPrivateKey, err1 := hex.DecodeString(privateKeyString)
	if err1 != nil {
		return nil, err1
	}

	privateKey, err2 := ethcrypto.ToECDSA(decodedPrivateKey)
	if err2 != nil {
		return nil, err2
	}

	return privateKey, nil
}

func Keccak256HashToStr(hash common.Hash) string {
	return hash.Hex()
}

func StrToKeccak256Hash(hashString string) (common.Hash) {
	return common.HexToHash(hashString)
}

func main() {
	// 生成公私钥对
	privateKey, err := ethcrypto.GenerateKey()
	if err != nil {
		log.Fatal(err)
	}

	// 获取公钥
	publicKey := privateKey.Public()

	// 打印公私钥
	privKeyStr := ECDSAPrivKeyToStr(privateKey)
	fmt.Printf("私钥: %s\n", privKeyStr)
	privKey2, _ := StrToECDSAPrivKey(privKeyStr)
	fmt.Printf("私钥2: %s\n", ECDSAPrivKeyToStr(privKey2))

	fmt.Printf("公钥: %x\n", ethcrypto.FromECDSAPub(publicKey.(*ecdsa.PublicKey)))

	// 要签名的数据
	message := []byte("Hello, World!")

	// 对数据进行哈希处理
	hash := ethcrypto.Keccak256Hash(message)
	hashStr := Keccak256HashToStr(hash)
	fmt.Printf("hashStr: %s\n", hashStr)
	hash2 := StrToKeccak256Hash(hashStr)
	fmt.Printf("hashStr2: %s\n", Keccak256HashToStr(hash2))

	// 对哈希进行签名
	signature, err := ethcrypto.Sign(hash.Bytes(), privateKey)
	if err != nil {
		log.Fatal(err)
	}

	// 打印签名结果
	fmt.Printf("签名: %s\n", hexutil.Encode(signature))

	// 从签名中恢复公钥
	recoveredPublicKey, err := ethcrypto.SigToPub(hash.Bytes(), signature)
	if err != nil {
		log.Fatal(err)
	}

	// 打印恢复的公钥
	fmt.Printf("恢复的公钥: %x\n", ethcrypto.FromECDSAPub(recoveredPublicKey))

	// 验证签名
	isValid := ethcrypto.VerifySignature(ethcrypto.CompressPubkey(recoveredPublicKey), hash.Bytes(), signature[:len(signature)-1])
	fmt.Printf("签名验证结果: %v\n", isValid)
}
